package com.zhs.elasticsearch.es.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zhs.elasticsearch.basic.AjaxResult;
import com.zhs.elasticsearch.es.UserTermSearchService;
import com.zhs.elasticsearch.match.eo.UserEO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *
 * @Author zhenghuisheng
 * @Date：2025/6/26 11:40
 */
@Service
@Slf4j
public class UserTermSearchServiceImpl implements UserTermSearchService {

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Override
    public AjaxResult matchSearch() {
        // 构建查询
        BoolQueryBuilder queryBuilder = buildBoolQueryBuilder1();
        // 设置查询源
        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
        sourceBuilder.query(queryBuilder);
        // 这里可以查看详细的请求 直接拿到kibana上执行
        log.info("构建条件为:,{}", sourceBuilder);
        sourceBuilder.size(10);
        // 构建查询请求
        SearchRequest searchRequest = new SearchRequest("user");
        searchRequest.source(sourceBuilder);
        List<UserEO> userMatchList = new ArrayList<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();
            log.info("匹配的返回结果为,{}", hits.length);
            // 强转eo返回
            userMatchList = convertToUserEoList(hits);
        } catch (Exception e) {
            log.error("matchSearch error:", e);
        }
        return AjaxResult.success(userMatchList);
    }


    private BoolQueryBuilder buildBoolQueryBuilder1() {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        boolQueryBuilder.should(QueryBuilders.matchQuery("regProvince.keyword", "上海市").boost(2));
//        boolQueryBuilder
//                .should(QueryBuilders.matchQuery("regCity.keyword", "北京市").boost(2))
//                .should(QueryBuilders.matchQuery("liveCity.keyword", "北京市").boost(3));

//        boolQueryBuilder.should(QueryBuilders.matchQuery("regCity.keyword", "北京市").boost(5));
//        QueryBuilders.multiMatchQuery("北京市", "liveCity.keyword^3", "regCity.keyword^2");

        boolQueryBuilder.should(QueryBuilders.matchQuery("liveCity.keyword", "上海市").boost(5));
        boolQueryBuilder.should(QueryBuilders.matchQuery("liveCity.keyword", "北京市").boost(4));

        return  boolQueryBuilder;
    }

    /**
     * 构造查询条件
     * @return
     */
    private BoolQueryBuilder buildBoolQueryBuilder() {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 精确查询
        // 添加查询条件
        // boolQueryBuilder.filter(QueryBuilders.termQuery("id", "拉萨市"));
        //boolQueryBuilder.filter(QueryBuilders.termQuery("liveCity.keyword", "拉萨市"));
//        boolQueryBuilder.filter(QueryBuilders.termsQuery("liveCity", Arrays.asList("贵阳市", "北京市")));

//        boolQueryBuilder.must(QueryBuilders.matchQuery("liveProvince", "西藏"));
//        boolQueryBuilder.must(QueryBuilders.multiMatchQuery("北京市", new String[]{"liveCity", "regCity"}));

        // 身高170-175
//        boolQueryBuilder.filter(QueryBuilders.rangeQuery("height").gte(170).lte(175));
//        // 1998-2001年出生的
//        boolQueryBuilder.filter(QueryBuilders.rangeQuery("birthYear").gte(1998).lte(2001));
//        // 体重在120-140
//        boolQueryBuilder.filter(QueryBuilders.rangeQuery("weight").gte(120).lte(140));

//        boolQueryBuilder.must(QueryBuilders.existsQuery("nickName"));
//        boolQueryBuilder.mustNot(QueryBuilders.termQuery("nickName.keyword", ""));

        // 构建must查询方式
        // 必须满足老家城市是在北京市、上海市、广州市、深圳市
//        String[] cityArray = {"北京市", "上海市", "广州市", "深圳市"};
//        boolQueryBuilder.must(QueryBuilders.termsQuery("regCity.keyword", cityArray));
//        // 必须满足当前生活城市是在广州市
//        boolQueryBuilder.must(QueryBuilders.termQuery("liveCity.keyword", "广州市"));
//        // 必须满足用户学历是博士 学历： 3=大专以下，4=大专，5=大学本科，6=硕士，7=博士
//        boolQueryBuilder.must(QueryBuilders.termQuery("eduLevel", 7));
//        // 必须满足用户用户身高大于180
//        boolQueryBuilder.must(QueryBuilders.rangeQuery("height").gte(180));
//        // 必须满足用户体重小于140
//        boolQueryBuilder.must(QueryBuilders.rangeQuery("weight").lte(140));

//        // 构建should查询方式
//        BoolQueryBuilder buildShouldQuery = QueryBuilders.boolQuery()
//                // 生日应该在2002-2003年区间
//                .should(QueryBuilders.rangeQuery("birthYear").gte(2002).lte(2003))
//                // 学历是硕士或者博士
//                .should(QueryBuilders.rangeQuery("eduLevel").gte(6).lte(7))
//                // 身高在180-185 区间
//                .should(QueryBuilders.rangeQuery("height").gte(180).lte(185));
//        // 执行should，设置最少满足两个条件
//        boolQueryBuilder.should(buildShouldQuery).minimumShouldMatch(2);

        // 构建must_not查询方式
        // 必须不是被注销或者黑名单用户
//        boolQueryBuilder.mustNot(QueryBuilders.termQuery("delFlag", 1));
//        // 出生年必须不是2000前用户
//        boolQueryBuilder.mustNot(QueryBuilders.termQuery("birthYear", 2000));
//        // 学历必须不是专科及一下 学历： 3=大专以下，4=大专，5=大学本科，6=硕士，7=博士
//        boolQueryBuilder.must(QueryBuilders.rangeQuery("eduLevel").lte(4));
//        // 体重必须不能大于140
//        boolQueryBuilder.must(QueryBuilders.rangeQuery("weight").gte(140));
//        // 身高必须不能低于180
//        boolQueryBuilder.must(QueryBuilders.rangeQuery("height").lte(180));

        // 构建filter过滤方式
        // 过滤出正常的用户
//        boolQueryBuilder.filter(QueryBuilders.termQuery("delFlag", 0));
//        // 过滤出性别为男的用户
//        boolQueryBuilder.filter(QueryBuilders.termQuery("sex", 1));
//        // 过滤出学历为本科的用户
//        boolQueryBuilder.filter(QueryBuilders.termQuery("eduLevel", 5));
//        // 过滤出居住在广州市的用户
//        boolQueryBuilder.filter(QueryBuilders.termQuery("liveCity.keyword", "广州市"));
//        // 过滤出体重在120-130的用户
//        boolQueryBuilder.filter(QueryBuilders.rangeQuery("weight").gte(120).lte(130));
//        // 过滤出身高在180-185的用户
//        boolQueryBuilder.filter(QueryBuilders.rangeQuery("height").gte(180).lte(185));
//
//        boolQueryBuilder.mustNot(QueryBuilders.termsQuery("userId", Arrays.asList(1,2,3,4,5,6,7,8)));

        // 组合代码
        // 必须满足是男性，用户是正常用户，不能是注销用户或者黑名单用户
        boolQueryBuilder.must(QueryBuilders.termQuery("sex", 1));
        boolQueryBuilder.must(QueryBuilders.termQuery("delFlag", 0));
        // 需要满足这个用户是生活在北京市或者身高在180以上，上面两个条件至少需要满足一个
        BoolQueryBuilder buildShouldQuery = QueryBuilders.boolQuery()
                .should(QueryBuilders.termsQuery("liveCity", "北京市"))
                .should(QueryBuilders.rangeQuery("height").gte(180));
        boolQueryBuilder.should(buildShouldQuery).minimumShouldMatch(1);
        // 筛选的用户学历不能低于本科，体重不能超过140
        boolQueryBuilder.mustNot(QueryBuilders.rangeQuery("eduLevel").lte(4));
        boolQueryBuilder.mustNot(QueryBuilders.rangeQuery("weight").gte(140));
        // 过滤出生日再2000年后出生的用户，并且老家必须是一线城市，即北上广深
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("birthYear").gte(2000));
        String []cityArray = {"北京市","上海市","广州市","深圳市"};
        boolQueryBuilder.filter(QueryBuilders.termsQuery("regCity.keyword", cityArray));

        return boolQueryBuilder;
    }

    public List<UserEO> convertToUserEoList(SearchHit[] hits) {
        if (hits.length == 0) {
            return new ArrayList<>();
        }
        JSONArray jsonArray = new JSONArray();
        for (SearchHit hit : hits) {
            JSONObject jsonObject = JSONUtil.parseObj(hit.getSourceAsMap());
            jsonArray.add(jsonObject);
        }
        return JSONUtil.toList(jsonArray, UserEO.class);
    }
}
